package org.libarae.communication.request;

import java.io.ByteArrayOutputStream;

import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Map;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.libarae.communication.HTTPUtils;
import org.libarae.communication.XmlParseException;
import org.libarae.communication.common.Type;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

public class LoginRequest extends Request {
	private String mUserName;
	private String mPassword;
	private String mServerPassword;

	public LoginRequest() {
		super(Type.LOGIN);
	}
	
	public LoginRequest(String userName, String password) {
		super(Type.LOGIN);
		this.mUserName = userName.toLowerCase();
		this.mPassword = password;
	}

	@Override
	public String createXML() throws XmlParseException {
		Document doc;
		try{
			//setup the factory to build the xml
			DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
			DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
			doc = documentBuilder.newDocument();
		}
		catch (Exception e) {
			throw new XmlParseException("Error creating XML Builder",e);
		}
		
		//create the xml
		Element rootElement = doc.createElement("type");
		rootElement.setAttribute("typeID", super.getType()+"");
		doc.appendChild(rootElement);
		//user name
		Element node = doc.createElement("mUserName");
		node.setTextContent(mUserName);
		rootElement.appendChild(node);
		
		//password
		//hash the password on the client side
		node = doc.createElement("mPassword");
		node.setTextContent(getMd5(mPassword));
		rootElement.appendChild(node);
		//server pass
		node = doc.createElement("mServerPassword");
		node.setTextContent(mServerPassword);
		rootElement.appendChild(node);
		
		node = doc.createElement("mAccessKey");
		node.setTextContent(getAccessKey());
		rootElement.appendChild(node);
		
		//export the xml to a string
		String output = null;
		try {
			ByteArrayOutputStream byteArrayOutput = new ByteArrayOutputStream();
			TransformerFactory transformerFactory = TransformerFactory.newInstance();
			Transformer transformer = transformerFactory.newTransformer();
			DOMSource source = new DOMSource(doc);
			StreamResult result = new StreamResult(byteArrayOutput);
			transformer.transform(source, result);
			output = byteArrayOutput.toString();
		}
		catch (Exception e) {
			throw new XmlParseException("Error outputting XML to string", e);
		}
		
		//return the string
		return output;
	}

	@Override
	public void decodeXML(Document doc) {
		// get the document root and node list
		Element root = doc.getDocumentElement();
		NodeList nodeList = root.getChildNodes();
		
		// set all of the nodes in their proper places
		for (int i = 0; i < nodeList.getLength(); i++) {
			// find what node we have
			String nodeName = nodeList.item(i).getNodeName();
			if (nodeName.equals("mUserName")) {
				mUserName = nodeList.item(i).getTextContent();
			}
			else if (nodeName.equals("mAccessKey")) {
				setAccessKey(nodeList.item(i).getTextContent());
			}
			else if (nodeName.equals("mPassword")) {
				mPassword = nodeList.item(i).getTextContent();
			}
			else if (nodeName.equals("mPassword")) {
				mPassword = nodeList.item(i).getTextContent();
			}
			else if (nodeName.equals("mServerPassword")) {
				mServerPassword = nodeList.item(i).getTextContent();
			}
			else {
				System.err.println("Unknow field in object XML: " + nodeName);
			}
		}
	}

	public String getUserName() {
		return mUserName;
	}

	public void setUserName(String mUserName) {
		this.mUserName = mUserName.toLowerCase();
	}

	public String getPassword() {
		return mPassword;
	}

	public void setPassword(String mPassword) {
		this.mPassword = mPassword;
	}
	
	/**
	 * @return the mServerPassword
	 */
	public String getServerPassword() {
		return mServerPassword;
	}

	/**
	 * @param mServerPassword the mServerPassword to set
	 */
	public void setServerPassword(String serverPassword) {
		this.mServerPassword = serverPassword;
	}


	@Override
	public String creatGET() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public void decodeGET(String postMessage) {
		
		Map<String, String> map = HTTPUtils.getParams(postMessage);

		if(!map.containsKey("mPassword") || !map.containsKey("mUserName"))
			return;//Bad request
		
		setUserName(map.get("mUserName"));
		setPassword(getMd5(map.get("mPassword")));		
	}
	
	public static String getMd5(String pInput){
		try {
			MessageDigest lDigest = MessageDigest.getInstance("MD5");
			lDigest.update(pInput.getBytes());
			BigInteger lHashInt = new BigInteger(1, lDigest.digest());
			return String.format("%1$032X", lHashInt);
		} catch(NoSuchAlgorithmException lException) {
			return null;
		}
	}	
}
